package com.gcloud.mesh.distributedSchedule.multiObjectiveScheduler;

import java.util.concurrent.ConcurrentHashMap;

import com.gcloud.mesh.distributedSchedule.ICluster;
import com.gcloud.mesh.distributedSchedule.IEvaluateFactor;
import com.gcloud.mesh.distributedSchedule.application.Application;
import com.gcloud.mesh.heuristicAlgorithm.geneticAlgorithm;

/**
 * 多目标调度器，基于遗传算法实现
 */
public class multiObjectiveScheduler {

    private ConcurrentHashMap<String, ICluster> clusterMap = null;

    /**
     * 多目标调度器初始化
     * @param initialCapacity 允许的集群数量，小于等于0表示没有限制
     */
    public multiObjectiveScheduler(int initialCapacity) {
        if (initialCapacity > 0)
            this.clusterMap = new ConcurrentHashMap<String, ICluster>(initialCapacity);
        else
            this.clusterMap = new ConcurrentHashMap<String, ICluster>();
    }

    public void addCluster(ICluster cluster) throws Exception {
        if (clusterMap.containsKey(cluster.getId())) {
            throw new Exception(String.format("cluster id existed [%s].", cluster.getId()));
        } else {
            this.clusterMap.put(cluster.getId(), cluster);
        }
    }

    public void updateCluster(ICluster cluster) throws Exception {
        this.clusterMap.put(cluster.getId(), cluster);
    }

    public void rmCluster(String clusterId) {
        this.clusterMap.remove(clusterId);
    }

    /**
     * 计算应用调度到那些集群
     * @param apps       要调度的应用集合，计算出的调度目标集群id更新到应用对象里面，通过getScheduleCluster()方法获取
     * @param clusters   应用可以调度到的目标集群集合
     * @param evaluators 评价算子集合
     * @return 是否得到合适的调度计算结果，如果为真则应用对象里会更新调度目标集群id，否则则不更新不返回集群id
     */
    public boolean schedule(ConcurrentHashMap<String, Application> apps,
                            ConcurrentHashMap<String, ICluster> clusters,
                            ConcurrentHashMap<String, IEvaluateFactor> evaluators) throws Exception {

        String[] clusterIds = clusters.keySet().toArray(new String[0]);
        Application[] appArray = apps.values().toArray(new Application[0]);
        IEvaluateFactor[] evlArray = evaluators.values().toArray(new IEvaluateFactor[0]);

        geneticAlgorithm ga = new geneticAlgorithm(appArray.length, clusterIds, 1, appArray.length * clusterIds.length);
        String[] clustersId = ga.evaluate(evlArray, appArray, clusters);
        // mod Application.scheduleToCluster.
        for (int i = 0; i < clusterIds.length; i++) {
            appArray[i].setMigrateCluster(clusterIds[i]);
        }

        return true;
    }
}
